#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

#include "utils.h"
#include "rf_utils.h"

// 仿真 IQ 数据缓存
// 加载的 IQ 数据文件名，如果相同的文件已经加载，则不再加载
static char   simulate_iq_file[256];
// IQ 数据缓冲区
static void*  simulate_iq_data = NULL;
// IQ 数据点数
static size_t simulate_iq_samplecount = 0;
// IQ 数据点数据类型(即实部和虚部的数据类型)
static iq_type_t simulate_iq_type = IQ_TYPE_NULL;
// IQ 数据额外信息（具体内容与文件类型有关）
static void*  simulate_iq_info = NULL;

void rf_iqcache_clear() {
    if (simulate_iq_data) { free(simulate_iq_data); simulate_iq_data = NULL; }
    if (simulate_iq_info) { free(simulate_iq_info); simulate_iq_info = NULL; }
    simulate_iq_samplecount = 0;
    simulate_iq_type = IQ_TYPE_NULL;
    simulate_iq_file[0] = '\0';
}

int rf_iq_type_size(iq_type_t iq_type) {
    static const int type_size_map[] = IQ_TYPE_SIZE_MAP;
    if (iq_type <= IQ_TYPE_NULL || iq_type >= IQ_TYPE_MAX) return 0;
    return type_size_map[iq_type];
}

iq_type_t rf_iq_filename_to_type(const char *fname_iq) {
    char ext[256];
    if (!fname_iq) return IQ_TYPE_NULL;
    _splitpath(fname_iq, NULL, NULL, NULL, ext);
    if (stricmp(ext, ".int16") == 0)  return IQ_TYPE_INT16;
    if (stricmp(ext, ".int32") == 0)  return IQ_TYPE_INT32;
    if (stricmp(ext, ".float") == 0)  return IQ_TYPE_FLOAT;
    if (stricmp(ext, ".double") == 0) return IQ_TYPE_DOUBLE;
    if (stricmp(ext, ".iqw") == 0)    return IQ_TYPE_FLOAT;
    return IQ_TYPE_NULL;
}

std_err_t rf_iqbuf_load_ni_csv(const char *fname_csv, iq_type_t iq_type, void **piqbuf, size_t *piqcount) {
    if(!fname_csv || iq_type <= IQ_TYPE_NULL || iq_type >= IQ_TYPE_MAX || !piqbuf) return STD_ERR_INVALID_ARG;
    if(piqcount) *piqcount = 0;

    std_err_t err = STD_ERR_OK;
    FILE *fcsv = NULL;
    void *iqbuf = NULL;
    int ret = 0, iqcount = 0;
    bool withtime = false;
    double fi, fq;
    char line[256];

    do {
        fcsv = fopen(fname_csv, "rt");
        if(!fcsv) { err = STD_ERR_NOT_FOUND; break; }

        while(fgets(line, sizeof(line), fcsv)) {
            // 数据前面有: "Sample Count,250000,250000" 表示数据格式为 "time,I,Q"
            // 数据前面有: "Sample Count,250000"        表示数据格式为 "I,Q"
            int dummy;
            ret = sscanf(line, "Sample Count,%d,%d", &iqcount, &dummy);
            if(ret) {
                if(ret >= 2) withtime = true;
                break;
            }
        }
        if(!ret) { err = STD_ERR_INVALID_VERSION; break; }

        iqbuf = malloc(iqcount * rf_iq_type_size(iq_type));
        if(!iqbuf) { err = STD_ERR_NO_MEM; break; }

        for(int i = 0; i < iqcount; i++) {
            if(!fgets(line, sizeof(line), fcsv)) { err = STD_ERR_EOF; break; }
   
            if(withtime) {
                // 数据格式为: time,I,Q
                // 如: 0.00041107600000002203,0.103843026,-0.23891203,
                double time;
                ret = sscanf(line, "%lf,%lf,%lf", &time, &fi, &fq);
                if(ret < 3) { err = STD_ERR_INVALID_VERSION; break; }
            } else {
                // 数据格式为: I,Q
                // 如: 0.103843026,-0.23891203,
                ret = sscanf(line, "%lf,%lf", &fi, &fq);
                if(ret < 2) { err = STD_ERR_INVALID_VERSION; break; }
            }

            if(iq_type == IQ_TYPE_INT16) {
                ((int16_t*)iqbuf)[2*i]     = (int16_t)(fi * INT16_MAX);
                ((int16_t*)iqbuf)[2*i + 1] = (int16_t)(fq * INT16_MAX);
            } else if(iq_type == IQ_TYPE_INT32) {
                ((int32_t*)iqbuf)[2*i]     = (int32_t)(fi * INT32_MAX);
                ((int32_t*)iqbuf)[2*i + 1] = (int32_t)(fi * INT32_MAX);
            } else if(iq_type == IQ_TYPE_FLOAT) {
                ((float*)iqbuf)[2*i]       = (float)fi;
                ((float*)iqbuf)[2*i + 1]   = (float)fq;
            } else if(iq_type == IQ_TYPE_DOUBLE) {
                ((double*)iqbuf)[2*i]      = (double)fi;
                ((double*)iqbuf)[2*i + 1]  = (double)fq;
            } else {
                err = STD_ERR_NOT_SUPPORTED;
            }
        }
    } while(0);

    if(fcsv) fclose(fcsv);
    if(err) { free(iqbuf); return err; }

    *piqbuf = iqbuf;
    if(piqcount) *piqcount = iqcount;
    return STD_ERR_OK;
}

std_err_t rf_iqbuf_load(const char *fname_iq, iq_type_t iq_type, void **piqbuf, size_t *piqcount) {
    if(iq_type == IQ_TYPE_NULL) iq_type = rf_iq_filename_to_type(fname_iq);
    if(!fname_iq || iq_type <= IQ_TYPE_NULL || iq_type >= IQ_TYPE_MAX || !piqbuf) return STD_ERR_INVALID_ARG;
    if(piqcount) *piqcount = 0;

    // 取得 IQ 文件大小
    struct stat fst;
    if(stat(fname_iq, &fst) < 0) return STD_ERR_FAIL;
    // 计算 IQ 数量
    size_t iqcount = fst.st_size / rf_iq_type_size(iq_type);

    // 打开 IQ 文件
    FILE *fiq = fopen(fname_iq, "rb");
    if(!fiq) return STD_ERR_FAIL;

    // 分配 IQ 缓冲区
    void *iqbuf = malloc(fst.st_size);
    if(!iqbuf) { fclose(fiq); return STD_ERR_NO_MEM; }

    // 读取 IQ 到缓冲区
    size_t rsize = fread(iqbuf, rf_iq_type_size(iq_type), iqcount, fiq);
    fclose(fiq);
    if(rsize != iqcount) { free(iqbuf); return STD_ERR_EOF; }
    
    *piqbuf = iqbuf;
    if(piqcount) *piqcount = iqcount;
    return STD_ERR_OK;
}

std_err_t rf_iqbuf_load_arb(const char *fname_arb, arb_info_t *arb_info, void **piqbuf, size_t *piqcount) {
    if(!fname_arb || !piqbuf) return STD_ERR_INVALID_ARG;
    if(piqcount) *piqcount = 0;

    std_err_t err = STD_ERR_OK;
    uint16_t* iqbuf = NULL;

    // 打开 ARB 文件
    FILE *fp = fopen(fname_arb, "rb");
    if(!fp) return STD_ERR_NOT_FOUND;

    // 分配 ARB 信息数据结构
    arb_info_t info;
    ZEROVAR(info);

    // 读取 ARB 文件头部信息
    // 头部文本信息格式: SAMPLES=15792;FREQUENCYSAMPLING=30720000;SIGNALBW=20000000;RMS=8471;PAR=9.4001;SOURCENAME=I:[I_WLAN30.72M_1CYCLE_25000.TXT]-Q:[Q_WLAN30.72M_1CYCLE_25000.TXT];GENERATEDDATETIME=2021-09-02 17:24:04;
    int n = fscanf(fp, "SAMPLES=%u;FREQUENCYSAMPLING=%u;SIGNALBW=%u;RMS=%lf;PAR=%lf;", &info.nsamples, &info.sample_rate, &info.bandwidth, &info.rms, &info.par);
    if(n != 5) { err = STD_ERR_INVALID_VERSION; goto _end; }
    if(info.nsamples < 1 || info.sample_rate < 1 || info.bandwidth < 1 || info.rms < 0 || info.par < 0) { err = STD_ERR_INVALID_VERSION; goto _end; }

    // 去掉16 KB 头部
    err = fseek(fp, 16 * 1024, SEEK_SET);
    if (err) { err = STD_ERR_EOF; goto _end; } // 文件意外结束

    // 数据大小
    size_t datasize = rf_iq_type_size(IQ_TYPE_INT16) * info.nsamples;    
    // 分配 IQ 缓冲区
    iqbuf = (uint16_t*)malloc(datasize);
    if (!iqbuf) { err = STD_ERR_NO_MEM; goto _end; }
    // 从文件读取数据
    if (fread(iqbuf, 1, datasize, fp) < datasize) { err = STD_ERR_EOF; goto _end; } // 文件意外结束

    *piqbuf = iqbuf;
    if(arb_info) memcpy(arb_info, &info, sizeof(*arb_info)); // 复制传出文件头信息
    if(piqcount) *piqcount = info.nsamples;
    err = STD_ERR_OK;

_end:
    if (fp) fclose(fp);
    if (err && iqbuf) free(iqbuf);
    return err;
}

iq_type_t rf_iqcache_get_iq_type() {
    return simulate_iq_type;
}

size_t rf_iqcache_get_iq_count() {
    return simulate_iq_samplecount;
}

void* rf_iqcache_get_iq_data() {
    return simulate_iq_data;
}

#define WRITE_IQ(srctype, dsttype, fiq)    do {         \
    size_t count = rf_iqcache_get_iq_count() * 2;       \
    srctype* buf = (srctype*)rf_iqcache_get_iq_data();  \
    dsttype val;                                        \
    for (size_t i = 0; i < count; i++) {                \
        val = (dsttype)(buf[i]);                        \
        ret = fwrite(&val, sizeof(dsttype), 1, fiq);    \
        if(ret != 1) err = STD_ERR_FAIL;                \
    }                                                   \
} while(0)

std_err_t rf_iqcache_save(const char *fname_iq, iq_type_t iq_type) {
    if (iq_type <= IQ_TYPE_NULL || iq_type > IQ_TYPE_MAX) iq_type = rf_iq_filename_to_type(fname_iq);
    if (!fname_iq || iq_type <= IQ_TYPE_NULL || iq_type >= IQ_TYPE_MAX) return STD_ERR_INVALID_ARG;
    if (!rf_iqcache_get_iq_data() || !rf_iqcache_get_iq_count()) return STD_ERR_INVALID_SIZE;
    std_err_t err = STD_ERR_OK;
    size_t ret;

    FILE *fiq = fopen(fname_iq, "wb");
    if(!fiq) return STD_ERR_FAIL;
    
    if(iq_type == rf_iqcache_get_iq_type()) {
        // 要保存的格式与缓存中的格式相同，可以直接保存
        ret = fwrite(rf_iqcache_get_iq_data(), rf_iqcache_get_iq_count() * rf_iq_type_size(rf_iqcache_get_iq_type()), 1, fiq);
        if(ret != 1) err = STD_ERR_FAIL;
    } else {
        // 要保存的格式与缓存中的格式不同，需要格式转换
        if(rf_iqcache_get_iq_type() == IQ_TYPE_INT16) {
            /**/ if (iq_type == IQ_TYPE_INT32)  WRITE_IQ(int16_t, int32_t, fiq);
            else if (iq_type == IQ_TYPE_FLOAT)  WRITE_IQ(int16_t, float,   fiq);
            else if (iq_type == IQ_TYPE_DOUBLE) WRITE_IQ(int16_t, double,  fiq);
            else err = STD_ERR_NOT_SUPPORTED;
        } else if(rf_iqcache_get_iq_type() == IQ_TYPE_INT32) {
            /**/ if (iq_type == IQ_TYPE_INT16)  WRITE_IQ(int32_t, int16_t, fiq);
            else if (iq_type == IQ_TYPE_FLOAT)  WRITE_IQ(int32_t, float,   fiq);
            else if (iq_type == IQ_TYPE_DOUBLE) WRITE_IQ(int32_t, double,  fiq);
            else err = STD_ERR_NOT_SUPPORTED;
        } else if(rf_iqcache_get_iq_type() == IQ_TYPE_FLOAT) {
            /**/ if (iq_type == IQ_TYPE_INT16)  WRITE_IQ(float, int16_t, fiq);
            else if (iq_type == IQ_TYPE_INT32)  WRITE_IQ(float, int32_t, fiq);
            else if (iq_type == IQ_TYPE_DOUBLE) WRITE_IQ(float, double,  fiq);
            else err = STD_ERR_NOT_SUPPORTED;
        } else if(rf_iqcache_get_iq_type() == IQ_TYPE_DOUBLE) {
            /**/ if (iq_type == IQ_TYPE_INT16)  WRITE_IQ(double, int16_t, fiq);
            else if (iq_type == IQ_TYPE_INT32)  WRITE_IQ(double, int32_t, fiq);
            else if (iq_type == IQ_TYPE_FLOAT)  WRITE_IQ(double, float,   fiq);
            else err = STD_ERR_NOT_SUPPORTED;
        } else {
            err = STD_ERR_NOT_SUPPORTED;
        }
    }

    fclose(fiq);
    return err;
}

std_err_t rf_iqcache_load_ni_csv(const char *fname_csv, iq_type_t iq_type) {
    if (!fname_csv || iq_type <= IQ_TYPE_NULL || iq_type >= IQ_TYPE_MAX) return STD_ERR_INVALID_ARG;

    // 如果此 IQ 文件已经加载，则直接返回
    if(strcmp(simulate_iq_file, fname_csv) == 0) return STD_ERR_OK;
    // 如果之前已经加载了缓存，则先清除它
    rf_iqcache_clear();

    std_err_t err = rf_iqbuf_load_ni_csv(fname_csv, iq_type, &simulate_iq_data, &simulate_iq_samplecount);
    if(err) return err;

    // 把当前 IQ 缓冲区数据做为缓存
    strncpy(simulate_iq_file, fname_csv, sizeof(simulate_iq_file)-1);
    simulate_iq_type = iq_type;
    return STD_ERR_OK;
}

std_err_t rf_iqcache_load(const char *fname_iq, iq_type_t iq_type) {
    if (iq_type == IQ_TYPE_NULL) iq_type = rf_iq_filename_to_type(fname_iq);
    if(!fname_iq || iq_type <= IQ_TYPE_NULL || iq_type >= IQ_TYPE_MAX) return STD_ERR_INVALID_ARG;

    // 如果此 IQ 文件已经加载，则直接返回
    if(strcmp(simulate_iq_file, fname_iq) == 0) return STD_ERR_OK;
    // 如果之前已经加载了缓存，则先清除它
    rf_iqcache_clear();
    
    // 从文件加载数据到缓冲区
    std_err_t err = rf_iqbuf_load(fname_iq, iq_type, &simulate_iq_data, &simulate_iq_samplecount);
    if(err) return err;

    // 把当前 IQ 缓冲区数据做为缓存
    strncpy(simulate_iq_file, fname_iq, sizeof(simulate_iq_file)-1);
    simulate_iq_type = iq_type;
    return STD_ERR_OK;
}

std_err_t rf_iqcache_load_arb(const char *fname_arb, arb_info_t *arb_info) {
    if(!fname_arb) return STD_ERR_INVALID_ARG;

    // 如果此 IQ 文件已经加载，则直接返回
    if(strcmp(simulate_iq_file, fname_arb) == 0) {
        if(arb_info) memcpy(arb_info, simulate_iq_info, sizeof(*arb_info));
        return STD_ERR_OK;
    }
    // 如果之前已经加载了缓存，则先清除它
    rf_iqcache_clear();
    
    // 创建 ARB 信息结构
    arb_info_t *info = MALLOC0(arb_info_t);
    if(!info) return STD_ERR_NO_MEM;
    
    // 从文件加载数据到缓冲区
    std_err_t err = rf_iqbuf_load_arb(fname_arb, info, &simulate_iq_data, &simulate_iq_samplecount);
    if(err) { free(info); return err; }

    // 把当前 IQ 缓冲区数据做为缓存
    strncpy(simulate_iq_file, fname_arb, sizeof(simulate_iq_file)-1);
    simulate_iq_type = IQ_TYPE_INT16;
    simulate_iq_info = info;
    if(arb_info) memcpy(arb_info, info, sizeof(arb_info_t));
    return STD_ERR_OK;
}
